package cn.xorange.commons.security.configuration;

import cn.xorange.commons.security.filter.JwtAuthTokenFilter;
import cn.xorange.commons.security.handler.AccessDeniedHandlerImpl;
import cn.xorange.commons.security.handler.AuthEntryPointHandler;
import cn.xorange.commons.security.handler.LogoutSuccessHandlerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.Resource;

/**
 * @author : yangjian
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfigure {

    @Resource
    IgnoreUrlConfigure ignoreUrlConfigure;
    @Resource
    LoginFilterConfig loginFilterConfig;
    @Resource
    LogoutSuccessHandlerImpl logoutSuccessHandler;
    @Resource
    AuthEntryPointHandler authEntryPointHandler;
    @Resource
    AccessDeniedHandlerImpl accessDeniedHandler;
    @Resource
    JwtAuthTokenFilter jwtAuthTokenFilter;
    /**
     * 跨域过滤器
     */
    @Autowired
    private CorsFilter corsFilter;




    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
                .cors()
                .and()
                // CSRF禁用，允许跨域
                .csrf().disable()
                // 禁用HTTP响应标头
                .headers((headersCustomizer) -> {
                    headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());
                })

                // 禁用form表单认证
                .formLogin().disable()
                // 基于token，所以不需要session
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 过滤请求
                .authorizeRequests()
                .antMatchers(this.ignoreUrlConfigure.getIgnoreStaticUrls()).permitAll()
                .antMatchers(this.ignoreUrlConfigure.getPassTokenUrls()).permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                // 自定义认证处理
                .and().addFilterBefore(jwtAuthTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 添加CORS filter
                .addFilterBefore(corsFilter, JwtAuthTokenFilter.class)
                .addFilterBefore(corsFilter, LogoutFilter.class)
                .apply(loginFilterConfig)
                .and()
                .logout().logoutUrl("/logout")
                .logoutSuccessHandler(logoutSuccessHandler)
                .invalidateHttpSession(true)
                .clearAuthentication(true)
                .deleteCookies()
                .and()
                //只允许用户在一个地方登陆，另一端登陆强制下线
                .sessionManagement().maximumSessions(1);

        // 认证失败和权限自定义异常处理
        httpSecurity.exceptionHandling()
                .authenticationEntryPoint(authEntryPointHandler)
                .accessDeniedHandler(accessDeniedHandler);
        return httpSecurity.build();
    }

    @Bean
    //启动过滤器链是很昂贵的，占用了系统很多资源，有时候我们经过一个路径（比如访问静态资源：图片，视频等），不需要进行认证和授权，也就不需要启动过滤器链，为了节约系统资源，可以通过重写configure(WebSecurity web)方法来禁用过滤器链
    public WebSecurityCustomizer ignoringCustomizer() {
        return (web) ->web.ignoring().antMatchers(this.ignoreUrlConfigure.getIgnoreStaticUrls());
    }



}
